#!/usr/bin/env python
#
# nxt_filer program -- Simple GUI to manage files on a LEGO Mindstorms NXT
# Copyright (C) 2006  Douglas P Lau
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

import cStringIO
import gtk
import os.path
import urllib2
import nxt.locator
from nxt.brick import FileFinder, FileReader, FileWriter

def read_file(b, fname):
    # FIXME: change to "with" syntax for python 2.5
    # with FileReader(b, fname) as r:
    #   with open(fname, 'wb') as f:
    #       for data in r:
    #           f.write(data)
    r = FileReader(b, fname)
    r.__enter__()
    try:
        f = open(fname, 'wb')
        try:
            for data in r:
                f.write(data)
        finally:
            f.close()
    finally:
        r.__exit__(None, None, None)

class NXTListing(gtk.ListStore):

    def __init__(self, brick):
        gtk.ListStore.__init__(self, str, str)
        self.set_sort_column_id(0, gtk.SORT_ASCENDING)
        self.populate(brick, '*.*')

    def populate(self, brick, pattern):
        # FIXME: change to "with" syntax for python 2.5
        # with FileFinder(b, pattern) as f:
        #    for (fname, size) in f:
        #        print '%s\t%s' % (fname, size)
        f = FileFinder(brick, pattern)
        try:
            for (fname, size) in f:
                self.append((fname, str(size)))
        finally:
            f.__exit__(None, None, None)

def write_file(b, fname, fil):
    # FIXME: change to "with" syntax for python 2.5
    # with FileWriter(b, fname) as w:
    #    for size in w:
    #        print 'Wrote %d bytes' % size
    w = FileWriter(b, fname, fil)
    w.__enter__()
    try:
        for size in w:
            print 'Wrote %d bytes' % size
    finally:
        w.__exit__(None, None, None)

def write_files(b, names):
    for fname in names.split('\r\n'):
        if fname:
            print 'File:', fname
            bname = os.path.basename(fname)
            url = urllib2.urlopen(fname)
            try:
                data = url.read()
            finally:
                url.close()
            print 'name %s, size: %d ' % (bname, len(data))
            fil = cStringIO.StringIO(data)
            try:
                write_file(b, bname, fil)
            finally:
                fil.close()

class NXT_Filer(gtk.Window):
    TARGETS = gtk.target_list_add_uri_targets()

    def __init__(self, brick):
        gtk.Window.__init__(self)
        self.brick = brick
        self.set_border_width(6)
        self.nxt_model = NXTListing(brick)
        h = gtk.HBox()
        h.pack_start(self.make_file_panel(str(brick.sock),
            self.nxt_model), True)
        self.add(h)
        self.connect('destroy', self.quit)

    def make_file_list(self):
        tv = gtk.TreeView()
        tv.set_headers_visible(True)
        tv.set_property('fixed_height_mode', True)
        r = gtk.CellRendererText()
        c = gtk.TreeViewColumn('File name', r, text=0)
        c.set_fixed_width(200)
        c.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
        tv.append_column(c)
        r = gtk.CellRendererText()
        c = gtk.TreeViewColumn('Bytes', r, text=1)
        c.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
        c.set_fixed_width(80)
        tv.append_column(c)

#            tv.enable_model_drag_source(gtk.gdk.BUTTON1_MASK, self.TARGETS,
#            gtk.gdk.ACTION_DEFAULT | gtk.gdk.ACTION_MOVE)
        tv.enable_model_drag_dest(self.TARGETS, gtk.gdk.ACTION_COPY)
#        tv.connect("drag_data_get", self.drag_data_get_data)
        tv.connect("drag_data_received", self.drag_data_received_data)

        return tv

    def make_file_panel(self, name, model):
        v = gtk.VBox()
        v.pack_start(gtk.Label(name), False)
        tv = self.make_file_list()
        tv.set_model(model)
        s = gtk.ScrolledWindow()
        s.set_policy(gtk.POLICY_NEVER, gtk.POLICY_ALWAYS)
        s.add(tv)
        s.set_border_width(2)
        v.pack_start(s, True)
        return v

    def drag_data_get_data(self, treeview, context, selection, target_id,
        etime):
        treeselection = treeview.get_selection()
        model, iter = treeselection.get_selected()
        data = model.get_value(iter, 0)
        print data
        selection.set(selection.target, 8, data)

    def drag_data_received_data(self, treeview, context, x, y, selection,
        info, etime):
        if context.action == gtk.gdk.ACTION_COPY:
            write_files(self.brick, selection.data)
        # FIXME: update file listing after writing files
        # FIXME: finish context

    def quit(self, w):
        'Quit the program'
        self.brick.sock.close()
        gtk.main_quit()

if __name__ == '__main__':
    # FIXME: add dialog with progress bar when scanning bluetooth devices
    sock = nxt.locator.find_one_brick()
    if sock:
        b = sock.connect()
        win = NXT_Filer(b)
        win.show_all()
        gtk.main()
